package gecko.dk;

import gecko.frame.*;
import gecko.impl.UdpServerTrigger;
import gecko.lang.JSONObject;
import gecko.lang.TypedMap;
import gecko.x.ByteX;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * 东控门禁UDP数据服务端
 *
 * @author 陈哈哈 (yoojiachen@gmail.com, chenyongjia@parkingwang.com)
 * @version 0.1
 */
public class DKAccessMonitorServer extends UdpServerTrigger {

    private static final Logger LOGGER = LoggerFactory.getLogger(DKAccessMonitorServer.class);

    private static FrameAdapter InstAdapter = new FrameAdapter();

    private static DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

    static {
        /*
        记录索引：3F 00 00 00
        记录类型：01
        有效状态：00
        开关编号：01
        进出方向：02
        操作卡号：D5 56 7D 00
        操作时间：20 18 12 20 15 49 39
        记录原因：06
        开关状态：01 01 00 00
        按钮状态：00 00 00 00
        故障状态：00
        主板时间：15 49 39
         */

        final TypeConverter b2i = new ByteToIntConverter();
        final TypeConverter b2b = new ByteToBooleanConverter();
        final TypeConverter b2of = new ByteToIntConverter() {
            @Override
            protected Object convert0(int value) {
                return value == 0 ? "OFF" : "ON";
            }
        };

        InstAdapter.addField(FrameField.INT("索引"));
        InstAdapter.addField(FrameField.BYTE("类型", b2i));
        InstAdapter.addField(FrameField.BYTE("有效", b2b));
        InstAdapter.addField(FrameField.BYTE("开关", b2i));
        InstAdapter.addField(FrameField.BYTE("方向", b2i));
        InstAdapter.addField(FrameField.ARRAY("卡号", 4));
        InstAdapter.addField(FrameField.ARRAY("时间", 7));
        InstAdapter.addField(FrameField.BYTE("原因", b2i));
        InstAdapter.addField(FrameField.BYTE("开关1", b2of));
        InstAdapter.addField(FrameField.BYTE("开关2", b2of));
        InstAdapter.addField(FrameField.BYTE("开关3", b2of));
        InstAdapter.addField(FrameField.BYTE("开关4", b2of));
        InstAdapter.addField(FrameField.BYTE("按钮1", b2of));
        InstAdapter.addField(FrameField.BYTE("按钮2", b2of));
        InstAdapter.addField(FrameField.BYTE("按钮3", b2of));
        InstAdapter.addField(FrameField.BYTE("按钮4", b2of));
        InstAdapter.addField(FrameField.BYTE("故障", b2i));
    }

    // 指定东控的数据报文协议解码接口
    public DKAccessMonitorServer() {
        setAdapter(new Adapter() {
            @Override
            public Collection<Event> decode(SocketAddress address, byte[] dataFrame) {
                final Instr inst;
                try {
                    inst = new Instr(dataFrame);
                } catch (Exception ex) {
                    LOGGER.error("数据不符合东控数据帧格式", ex);
                    return null;
                }
                // 检查为实时监控报文
                if (DKFunID.BOARD_STATE != inst.FUN_ID) {
                    return Collections.emptyList();
                } else {
                    final JSONObject instDataFields = InstAdapter.parse(inst.DATA, ByteOrder.LITTLE_ENDIAN);
                    final List<Event> ret = new ArrayList<>();
                    // 报警信息
                    if (TypedMap.wrap(instDataFields).getBoolean("故障")) {
                        ret.add(new Event(
                                "/dongkong/errors/" + inst.DEV_SN,
                                new JSONObject()
                                        .field("地址", address.toString())
                                        .field("序列", String.valueOf(inst.DEV_SN))
                                        .field("原因", "内部硬件故障")
                                        .field("时间", DT_FORMATTER.format(LocalDateTime.now()))
                        ));
                    }
                    // 监控状态信息
                    ret.add(new Event("/dongkong/update/" + inst.DEV_SN,
                            new JSONObject()
                                    .field("地址", address.toString())
                                    .field("序列", String.valueOf(inst.DEV_SN))
                                    .field("流水", String.valueOf(inst.SEQ_ID))
                                    .field("指令", ByteX.hex(inst.FUN_ID))
                                    .fields(instDataFields)));


                    return ret;
                }
            }

            @Override
            public byte[] encode(SocketAddress address, JSONObject data) {
                return data.toJSONBytes();
            }
        });
    }

}
